<?php

class Helper_Render
{
    /**
     * @param array $rows
     * @return array with structure.
     */
    public function prepareElements($rows)
    {

        $areas = array();
        $maps = array();
        $result = array();

        foreach ($rows as $row)
        {
            if (0 == $row['pid'])
            {
                $areas[$row['id']] = $row['area'];
            }
            $maps[$row['id']] = $this -> prepareElement($row);
        }

        unset($rows);

        $nest = array(
            'block' => array('list', ),
            'list' => array('list', ),
        );

        /**
         * layout contain area
         * area contain /list/block
         * list contain list/block
         * block contain block
         */
        foreach ($nest as $type => $parentTypes)
        {
            foreach ($parentTypes as $parentType)
            {
                foreach ($maps as $index => $row)
                {
                    if ($type == $row['type'])
                    {
                        $pid = $row['pid'];
                        if (isset($maps[$pid]) && isset($maps[$pid]['type']) && $parentType == $maps[$pid]['type'])
                        {
                            $maps[$pid]['children'][] = $row;
                            unset($maps[$index]);
                            // remote from maps.
                        }
                    }
                }
            }
        }

        foreach ($areas as $id => $area)
        {
            $result[$area][] = $maps[$id];
        }
        // unset all maps.
        unset($maps);

        return $result;
    }

    public function prepareElement($row)
    {
        if (!isset($row['children']))
        {
            $row['children'] = array();
        }
        return $row;
    }

    public function getAvailableActionList($actionId)
    {
        $result = array($actionId);
        $arr = preg_split('#\W#', $actionId);
        $m_first = array_shift($arr);
        $m_mid = $arr[0];
        $m_end = array_pop($arr);
        $m_remain = implode('.', $arr);

        $result[] = sprintf('%s@%s', $m_first, $m_remain);
        $result[] = sprintf('%s@%s', $m_first, $m_mid);
        $result[] = sprintf('core@%s', $m_remain);
        $result[] = sprintf('core@%s', $m_mid);
        $result[] = 'core@';
        $result = array_unique($result);
        return $result;
    }

    public function loadLayout($name, $actionId, $siteId)
    {
        $key = Agis::getHelper('@string') -> createHash($name, $actionId, $siteId);

        $cache = Agis::getHelper('@cache') -> getCache('core');

        if (false !== ($result = $cache -> load($key)))
        {
            return $result;
        }

        $actionList = $this -> getAvailableActionList($actionId);

        $table = Agis::getTable('core@render.layout');

        // echo sprintf("get layout match [%s]", implode(';', $actionList));

        $select = $table -> select() -> where('layout_name=?', $name) -> where('action_id IN (?)', $actionList) -> order('action_id DESC');

        $layout = $table -> fetchRow($select);

        $id = intval($layout -> layout_id);

        $table = Agis::getTable('core@render.element');

        $select = $table -> select() -> where('layout_id=?', $id) -> order('priority ASC');

        $areas = $this -> prepareElements($table -> fetchAll($select) -> toArray());

        $result = array(
            $layout -> toArray(),
            $areas
        );

        $cache -> save($result, $key);

        return $result;
    }

    /**
     * $ele = array('id'=>int,
     * 'action_id'=>'string','params'=>string,'children'=>array())
     * @param array $ele
     * @param string $actionId
     * @return string
     */
    public function renderElement($element = null)
    {
        $params = array();
        $type = $element['type'];
        $spec = $element['spec'];

        if ('list' == $type)
        {
            /**
             * check spec to render.
             */
        }
        else
        if ('block' == $type)
        {
            $params = array();

            $request = new Request();

            $html = $request -> setParams($params) -> setHandlerId($element['name']) -> execute() -> content;

            unset($request);

            return sprintf("<div>%s</div>", $html);
        }

    }

    /**
     * $eles = array[array('id'=>int,
     * 'action_id'=>'string','params'=>string,'children'=>array())]
     * @param array $blocks
     *
     */
    public function renderElements($elements)
    {
        $xhtml = array();
        if (is_array($elements))
        {
            foreach ($elements as $element)
            {

                $xhtml[] = $this -> renderElement($element, null);

            }

        }
        return implode(PHP_EOL, $xhtml);
    }

    /**
     * check if accept empty content.
     */
    public function renderArea($allAreas, $areaName, $acceptEmpty = false)
    {
        $html = '';
        $area = isset($allAreas[$areaName]) ? $allAreas[$areaName] : array();

        if (!empty($area))
        {
            $html = $this -> renderElements($area);
        }

        if ($acceptEmpty == false && '' == $html)
        {
            return;
        }

        return sprintf('<div class="layout-area-%s">%s</div>', $areaName, $html);
    }

    /**
     * @param string $region
     * @param array $areas
     * @return string
     */
    public function renderLayout($name, $actionId = null, $siteId = null)
    {

        /**
         * load section layout
         */
        list($layout, $areas) = $this -> loadLayout($name, $actionId, $siteId);

        if (null == $layout)
        {
            return '';
        }

        $script = 'layout/areas/' . $layout['layout_script'] . '.tpl';

        return View::getInstance()->render(array(
            'parser' => $this,
            'layout' => $name,
            'areas' => $areas,
            'actionId' => $actionId,
            'siteId' => $siteId,
        ), $script);
    }

    /**
     * process render layout
     * @param string $page
     * @param string $actionId
     * @param int $siteId
     * @return string
     */
    protected function _renderPage($page = null, $actionId = null, $siteId = null)
    {
        if (null == $siteId)
        {
            $siteId = Agis::get('siteId');
        }

        if (null == $actionId)
        {
            $actionId = Agis::getRequest() -> getHandlerId();
        }

        if (null == $page)
        {
            $page = 'default';
        }

        $script = 'layout/pages/' . $page . '.tpl';

        return View::getInstance()->render(array(
            'page' => $page,
            'actionId' => $actionId,
            'siteId' => $siteId,
            'parser' => $this
        ), $script);
    }

    public function renderPage($page, $actionId = null, $siteId = null)
    {

        Agis::fireEvent('onRenderPageStartup');

        $content = $this -> _renderPage($page, $actionId);

        Agis::fireEvent('onRenderPageShutdown');

        $head = Agis::getHelper('@head');

        return '<html><head>' . $head . '</head><body>' . $content . '</body>' . '</html>';
    }

}
